package com.gitee.wsl.ext.base


import arrow.core.Either
import com.gitee.wsl.ext.base.BooleanExt.FALSE_SET
import com.gitee.wsl.ext.base.BooleanExt.TRUE_SET
import com.gitee.wsl.ext.string.isNotEmpty
import com.gitee.wsl.struct.either.toLeft
import com.gitee.wsl.struct.either.toRight
import timber.log.Timber
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.time.Duration
import kotlin.time.DurationUnit


/*infix fun <T> Boolean.then(value: T?) = TernaryExpression(this, value)

class TernaryExpression<out T>(val flag: Boolean, private val truly: T?) {
    infix fun <T> or(falsy: T?) = if (flag) truly else falsy
}*/


object BooleanExt{
    /** 表示为真的字符串  */
     val TRUE_SET: Set<String> = setOf("true", "yes", "y", "t", "ok", "1", "on", "是", "对", "真", "對", "√")

    /** 表示为假的字符串  */
     val FALSE_SET: Set<String> = setOf("false", "no", "n", "f", "0", "off", "否", "错", "假", "錯", "×")
}

fun Boolean?.orFalse(): Boolean = this ?: false

fun Boolean.toChar():Char = toInt().toChar()

/** Converts this [Boolean] into integer: 1 for true, 0 for false */
 fun Boolean.toInt(): Int = if (this) 1 else 0

 fun Boolean.toByte(): Byte = if (this) 1 else 0

 fun Byte.toBoolean(): Boolean = this.toInt() != 0

/**
 * @return false if zero, else true
 */
fun Int.toBoolean(): Boolean = this != 0

/**
 * Extracts the bits from the byte in left to right order.
 * @return the bits as a collection of boolean
 */
fun Byte.toBits(): List<Boolean>
{
    val flags = mutableListOf<Boolean>()
    (7 downTo 0).forEach { index ->
        // Mask with 1 to compare against the bit only and get a remainder of either 0 or 1.
        val bit = (this.toInt() shr index) and 1
        flags.add(bit.toBoolean())
    }
    return flags
}

/**
 * Object 转 Boolean
 * @param value        Value
 * @param defaultValue 默认值
 * @return Boolean, 如果转换失败则返回 defaultValue
 */
fun String?.asBoolean(
    defaultValue: Boolean = false,
): Boolean {
    var strValue = this ?: return defaultValue
    try {
        strValue = strValue.lowercase()
        // true、t、yes、y、1
        if (TRUE_SET.contains(strValue)) {
            return true
        }
        // false、f、no、n、0
        if (FALSE_SET.contains(strValue)) {
            return false
        }

        throw Exception("can not cast to boolean, value : $this")
    } catch (e: Exception) {
        Timber.d( e, "toBoolean")
    }

    return defaultValue
}

/**
 * Description: 针对布尔值的相关扩展拆分
 * @author Junerver
 * date: 2024/2/5-9:17
 * Email: junerver@gmail.com
 * Version: v1.0
 */

/**
 * 将任意值转换成布尔，类似JS的 Boolean包装器函数
 */
fun toBoolean(value: Any?): Boolean {
    return when (value) {
        null -> false //空对象直接返回 false
        is Boolean -> value //布尔类型返回自身
        is Number -> value != 0 //数值类型非0
        is String -> value.isNotEmpty() && value != "false" && value != "null" //空字符、'false'、'null'
        is Array<*> -> value.isNotEmpty() //数组、集合必须有元素
        is Collection<*> -> value.isNotEmpty()
        is Map<*, *> -> value.isNotEmpty()
        is Duration -> value.toLong(DurationUnit.MILLISECONDS) > 0//如果是时间，时间大于0
        else -> true
    }
}


@OptIn(ExperimentalContracts::class)
fun Any?.asBoolean(): Boolean {
    contract {
        returns(true) implies (this@asBoolean != null)
    }
    return toBoolean(this)
}


infix fun  Boolean.isTrue(callBack:()->Unit):Boolean{
    if (this) callBack()
    return this
}

infix fun  Boolean.isFalse(callBack:()->Unit):Boolean{
    if (!this) callBack()
    return this
}

infix fun <T> Boolean.trueValue(trueValue: T):T?{
    if (this) return trueValue
    return null
}

infix fun <T> Boolean.falseValue(falseValue: T):T?{
    if (!this) return falseValue
    return null
}

infix fun <T> Boolean.trueValue(callBack:()->T):T?{
    if (this) return callBack()
    return null
}

infix fun <T> Boolean.falseValue(callBack:()->T):T?{
    if (!this) return callBack()
    return null
}

fun <T> Boolean.ifValue(trueValue: T,falseValue:T):T{
    return if (this) trueValue else falseValue
}

infix fun Boolean.ifTrue(trueCallBack:()->Unit):ThenCheck{
    val booleanValue = this
    if(booleanValue) trueCallBack()
    return ThenCheck { falseCallBack -> if(!booleanValue) falseCallBack() }
}

fun interface ThenCheck{
    fun elseThen(callBack:()->Unit)
}

fun List<Boolean>.allTrue():Boolean = isNotEmpty() && !contains(false)

fun List<Boolean>.anyTrue():Boolean = isNotEmpty() && contains(true)

inline fun <T> T.eq(other:T,trueCallBack:()->Unit){
    if(this == other) trueCallBack()
}

fun <T:Any> Long.is0(trueValue:T, falseValue:T):T{
    return if(this == 0L) trueValue else falseValue
}

fun <T:Any> Long.is0(trueValue:T):T?{
    return if(this == 0L) trueValue else null
}

fun <T:Any> Long.isNot0(trueValue:T):T?{
    return if(this != 0L) trueValue else null
}

fun <T> Int.is0(trueValue:T, falseValue:T):T{
    return if(this == 0) trueValue else falseValue
}

fun <T:Any> Int.is0(trueValue:T):T?{
    return if(this == 0) trueValue else null
}

fun <T:Any> Int.isNot0(trueValue:T):T?{
    return if(this != 0) trueValue else null
}

fun <T> Float.is0(trueValue:T, falseValue:T):T{
    return if(this == 0f) trueValue else falseValue
}

fun <T:Any> Float.is0(trueValue:T):T?{
    return if(this == 0f) trueValue else null
}

fun <T:Any> Float.isNot0(trueValue:T):T?{
    return if(this != 0f) trueValue else null
}

fun <T> Double.is0(trueValue:T, falseValue:T):T{
    return if(this == 0.0) trueValue else falseValue
}

fun <T:Any> Double.is0(trueValue:T):T?{
    return if(this == 0.0) trueValue else null
}

fun <T:Any> Double.isNot0(trueValue:T):T?{
    return if(this != 0.0) trueValue else null
}

/**
 * Description:
 * @author Junerver
 * date: 2023/11/1-15:38
 * Email: junerver@gmail.com
 * Version: v1.0
 */

/**
 * 将一个 Boolean 转成 Either 方便进行 fold 函数调用。
 * 作用类似于 [switches]，但是转成Either包装更方便
 */
fun Boolean.toEither(): Either<Boolean, Boolean> = if (this) true.toRight() else true.toLeft()

/**
 * 将boolean转换为字符串 `'true'` 或者 `'false'`.
 *
 * <pre>
 * BooleanUtil.toStringTrueFalse(true)   = "true"
 * BooleanUtil.toStringTrueFalse(false)  = "false"
</pre> *
 *
 * @param bool Boolean值
 * @return `'true'`, `'false'`
 */
fun Boolean.toStringTrueFalse(): String {
    return toString("true", "false")
}

/**
 * 将boolean转换为字符串 `'on'` 或者 `'off'`.
 *
 * <pre>
 * BooleanUtil.toStringOnOff(true)   = "on"
 * BooleanUtil.toStringOnOff(false)  = "off"
</pre> *
 *
 * @param bool Boolean值
 * @return `'on'`, `'off'`
 */
fun Boolean.toStringOnOff(): String {
    return toString( "on", "off")
}

/**
 * 将boolean转换为字符串 `'yes'` 或者 `'no'`.
 *
 * <pre>
 * BooleanUtil.toStringYesNo(true)   = "yes"
 * BooleanUtil.toStringYesNo(false)  = "no"
</pre> *
 *
 * @param bool Boolean值
 * @return `'yes'`, `'no'`
 */
fun Boolean.toStringYesNo(): String {
    return toString("yes", "no")
}

/**
 * 将boolean转换为字符串
 *
 * <pre>
 * BooleanUtil.toString(true, "true", "false")   = "true"
 * BooleanUtil.toString(false, "true", "false")  = "false"
</pre> *
 *
 * @param bool Boolean值
 * @param trueString 当值为 `true`时返回此字符串, 可能为 `null`
 * @param falseString 当值为 `false`时返回此字符串, 可能为 `null`
 * @return 结果值
 */
fun Boolean.toString(trueString: String, falseString: String): String {
    return if (this) trueString else falseString
}